class parallelcoord {
    constructor(svg_id) {
        this.width = 613
        this.height = 600
        this.svg = d3.select('#' + svg_id)
            .attr("width", this.width)
            .attr("height", this.height)
            .attr("viewBox", [0, 0, this.width, this.height])
    }

    clear() {
        this.svg.selectAll("*").remove()
    }

    vis(data, selected_list) {
        let K = []
        Object.keys(data[0]).forEach(k => {
            if (k!='x' && k!='y')
                K.push(k)
        });
        const marginTop = 30;
        const marginRight = 10;
        const marginBottom = 30;
        const marginLeft = 20;
        const keyz = K[0]
        const xScale = new Map(Array.from(K, key => [key, d3.scaleLinear(d3.extent(data, d => d[key]), [marginLeft, this.width - marginRight])]))
        const yScale = d3.scalePoint(K, [marginTop, this.height - marginBottom])
        const zScale = d3.scaleSequential(xScale.get(keyz).domain().reverse(), d3.interpolateWarm)

        const path = this.svg.append("g")
            .attr("fill", "none")
            .attr("stroke-width", 1.5)
            .attr("stroke-opacity", 0.2)
            .selectAll("path")
            .data(data.slice().sort((a, b) => d3.ascending(a[keyz], b[keyz])))
            .join("path")
            // .enter()
            // .append("path")
            .attr("stroke", d => zScale(d[keyz]))
            .attr("d", d => d3.line()
                .defined(([, value]) => value != null)
                .x(([key, value]) => xScale.get(key)(value))
                .y(([key]) => yScale(key))
                (d3.cross(K, [d], (key, d) => [key, d[key]])))
        
        path.append("title")
            .text(d => d.id);

        const brushHeight = 50
        const brush = d3.brushX()
            .extent([
                [marginLeft, -(brushHeight / 2)],
                [this.width - marginRight, brushHeight / 2]
            ])
            .on("start brush end", brushed);

        const selections = new Map();
        const deselectedColor = '#ddd'

        this.svg.append("g")
            .selectAll("g")
            .data(K)
            .join("g")
            // .enter()
            // .append("g")
            .attr("transform", d => `translate(0,${yScale(d)})`)
            .each(function (d) { d3.select(this).call(d3.axisBottom(xScale.get(d))); })
            .call(g => g.append("text")
                .attr("x", marginLeft)
                .attr("y", -6)
                .attr("text-anchor", "start")
                .attr("fill", "currentColor")
                .text(d => d))
            .call(g => g.selectAll("text")
                .clone(true).lower()
                .attr("fill", "none")
                .attr("stroke-width", 1)
                .attr("stroke-linejoin", "round")
                .attr("stroke", "white"))
            .call(brush);

        let svg = this.svg

        function brushed({ selection }, key) {
            if (selection === null) selections.delete(key);
            else selections.set(key, selection.map(xScale.get(key).invert));
            const selected = [];
            path.each(function (d) {
                const active = Array.from(selections).every(([key, [min, max]]) => d[key] >= min && d[key] <= max);
                d3.select(this).style("stroke", active ? zScale(d[keyz]) : deselectedColor);
                if (active) {
                    d3.select(this).raise();
                    selected.push(d);
                }
            });
            selected_list.length = 0
            for (let index = 0; index < selected.length; index++) {
                selected_list[index] = selected[index].id;
            }
            // d3.selectAll("circle").dispatch("selected", { 
            //     detial: {
            //         'selected': selected_list,
            //     } 
            // })

            svg.property("value", selected).dispatch("input");
        }

    }
}